package cn.heiliu.selenium.service.impl;

import cn.heiliu.selenium.config.SetupConfig;
import cn.heiliu.selenium.domain.SeleniumProxy;
import cn.heiliu.selenium.domain.WebDriverStatus;
import cn.heiliu.selenium.exception.DownFileTimeOutException;
import cn.heiliu.selenium.service.IWebDriverGetService;
import cn.heiliu.selenium.service.IWebDriverService;
import cn.hutool.system.OsInfo;
import cn.hutool.system.SystemUtil;
import com.google.common.collect.ImmutableMap;
import org.openqa.selenium.NoSuchWindowException;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.firefox.FirefoxOptions;
import org.openqa.selenium.remote.Response;

import java.nio.file.Path;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * @author wangyelou
 * @date 2021/6/14
 */
public class FirefoxWebDriverServiceImpl extends FirefoxDriver implements IWebDriverService {

    private static final String INSTALL_EXTENSION = "installExtension";
    private static final long DEFAULT_TIME_OUT = 10000;
    private static final String FIREFOX_SPECIAL_URL_PREFIX = "about:";
    private static AtomicInteger num = new AtomicInteger(1);

    /**
     * 启动配置
     */
    private SetupConfig setupConfig;

    /**
     * 浏览器名称
     */
    private String name;

    /**
     * 浏览器id
     */
    private String uid;

    /**
     * 当前浏览器的下载目录
     */
    private String ownDownDir;

    /**
     * 状态记录
     */
    private WebDriverStatus status;

    /**
     * 当前系统信息
     */
    private OsInfo osInfo = SystemUtil.getOsInfo();

    public FirefoxWebDriverServiceImpl(FirefoxOptions firefoxOptions, SetupConfig setupConfig, String uid) {
        super(firefoxOptions);
        this.setupConfig = setupConfig;
        this.uid = uid;
        this.name = "firefox-" + uid + "-" + num.getAndIncrement();
        this.ownDownDir = setupConfig.getDownDir(uid);
        num.compareAndSet(10000, 1);
        status = new WebDriverStatus();
    }

    /**
     * 安装临时插件
     * temporary 是否是临时插件
     * @param path 插件位置，绝对路径
     */
    @Override
    public void installExt(Path path) {
        execute(INSTALL_EXTENSION,
                ImmutableMap.of("path", path.toAbsolutePath().toString(),
                        "temporary", true)).getValue();
    }

    @Override
    public String getFlag() {
        return name;
    }

    @Override
    public IWebDriverGetService fetch(String url, SeleniumProxy proxy, String waitXpath, long timeout) {
        try {
            FirefoxWebDriverGetServiceImpl webGet = new FirefoxWebDriverGetServiceImpl(this, ownDownDir, url, timeout);
            webGet.setWaitXpath(waitXpath);
            if (proxy != null && !proxy.isEmpty()) {
                webGet.setProxy(proxy);
            }
            webGet.get();
            return webGet;
        } catch (DownFileTimeOutException e) {
            // 浏览器文件下载超时，但是浏览器本身还在下载，需要强制关闭浏览器
            this.quit();
            throw e;
        } catch (Exception e) {
            status.failed();
            throw e;
        }
    }

    @Override
    public IWebDriverGetService fetch(String url, SeleniumProxy proxy) {
        return fetch(url, proxy, null, DEFAULT_TIME_OUT);
    }

    @Override
    public IWebDriverGetService fetch(String url, String waitXpath, long timeout) {
        return fetch(url, null, waitXpath, timeout);
    }

    /**
     * 如果访问配置页面，则使用原来的get
     * @param url
     */
    @Override
    public IWebDriverGetService fetch(String url) {
        if (url.indexOf(FIREFOX_SPECIAL_URL_PREFIX) == 0) {
            super.get(url);
            return new FirefoxWebDriverGetServiceImpl();
        } else {
            return fetch(url, null, null, DEFAULT_TIME_OUT);
        }
    }

    /**
     * 每次操作浏览器都检测下窗口是否正确
     * @param driverCommand
     * @param parameters
     * @return
     */
    @Override
    protected Response execute(String driverCommand, Map<String, ?> parameters) {
        while (true) {
            try {
                return super.execute(driverCommand, parameters);
            } catch (NoSuchWindowException e) {
                String s = getWindowHandles().toArray()[0].toString();
                switchTo().window(s);
                System.out.println(s);
                parameters = ImmutableMap.of("handle", s);
            }
        }
    }

    @Override
    public WebDriverStatus getStatus() {
        return status;
    }


    @Override
    public String resetWindow() {
        String currentWindow;
        try {
            currentWindow = getWindowHandle();
        } catch (NoSuchWindowException e) {
            currentWindow = getWindowHandles().toArray()[0].toString();
        }

        // 关闭除当前标签的所有标签
        String finalCurrentWindow = currentWindow;
        getWindowHandles().forEach(window -> {
            if (!window.equals(finalCurrentWindow)) {
                switchTo().window(window);
                close();
            }
        });
        switchTo().window(finalCurrentWindow);
        return currentWindow;
    }

    @Override
    public void quit() {
        status.invalid();
        // 强制关闭
        try {
            long pid = (long) getCapabilities().getCapability("moz:processID");
            if (osInfo.isWindows()) {
                Runtime.getRuntime().exec("taskkill /pid " + pid + " -t -f");
            } else if (osInfo.isLinux()) {
                Runtime.getRuntime().exec("kill -9 " + pid);
            }
            super.quit();
        } catch (Exception e) {
            // 不输出
        }
    }


}
